﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using Core.ChannelProtocol;
using Core.Modbus;
using Core.Model;
using Core.Msg;
using log4net;

namespace Core.DeviceProtocol
{
    public abstract class BaseDevProtocol
    {
        protected static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
        public BaseChannel Channel { get; protected set; }
        public Device Dev { get; protected set; }
        public Dictionary<string,Operation> Operations { get; } = new Dictionary<string, Operation>();
        public List<DataItem> DataItems { get; } = new List<DataItem>();
        public virtual bool Initialize(BaseChannel channel,Device dev,List<Operation> operations, List<DataItem> dataItems)
        {
            Channel = channel;
            Dev = dev;
            if (operations != null&& operations.Count>0)
            {
                foreach (Operation sss in operations)
                {
                    Operations.Add(sss.Id,sss);
                }
            }
            if (dataItems != null && dataItems.Count > 0)
            {
                DataItems.Clear();
                DataItems.AddRange(dataItems);
            }
            if(Dev!= null)
                Dev.PropertyChanged += Dev_PropertyChanged;
            return true;
        }
        public virtual List<DataItem> GetInitDataItems(Device dev)
        {
            return null;
        }
        private void Dev_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "IsConnected")
            {
                if (!Dev.IsConnected)
                {
                    foreach (DataItem item in DataItems)
                    {
                        item.CurValue = 0;
                    }
                }
                else
                {
                    foreach (DataItem item in DataItems)
                    {
                        item.UpdateTime = DateTime.Now;
                    }
                }
            }
        }

        protected void MsgLog(bool error, string content)
        {
            if(error)
                _log.Error(content);
            else
                _log.Info(content);
        }
        public virtual bool RunPolling()
        {
            return false;
        }
        /// <summary>
        /// 处理报文中的地址和参数
        /// </summary>
        /// <param name="oper"></param>
        /// <param name="paras"></param>
        /// <returns></returns>
        public Operation DealOperationWithPara(Operation oper,string[] paras)
        {
            Operation dest = new Operation(oper);

            // 处理地址
            bool bMatch = false;
            if (dest.IsAscii)
            {
                Regex regex = new Regex(@"@(.*?)@");
                if (regex.IsMatch(dest.MsgContent))
                {
                    dest.MsgContent = regex.Replace(dest.MsgContent, "{0:$1}");
                    bMatch = true;
                }
            }
            else
            {
                dest.MsgContent = dest.MsgContent.Replace("@", Dev.Address.ToString());
            }
            if (paras != null && paras.Length > 0)
            {
                object[] temp = new object[paras.Length + 1];
                int index = 1;
                temp[0] = Dev.Address;
                foreach (string s in paras)
                {
                    temp[index] = s;
                    index++;
                }
                dest.MsgContent = string.Format(dest.MsgContent, temp);
            }
            else
            {
                if (dest.IsAscii && bMatch)
                    dest.MsgContent = string.Format(dest.MsgContent, Dev.Address);
            }
            return dest;
        }

        public virtual RxTxCommand PostToExcute(string operid)
        {
            throw new NotImplementedException("执行命令方法未实现!");
        }

        public virtual RxTxCommand PostToExcute(string operid,string[] paras)
        {
            throw new NotImplementedException("执行命令方法未实现!");
        }

        public virtual bool LoadDataItems()
        {
            List<DataItem> dataItems = Global.DataAccess.GetDataItems(Dev.Id);
            if (dataItems == null)
                return false;
            DataItems.Clear();
            DataItems.AddRange(dataItems);
            return true;
        }

        public virtual List<DataItem> SerializeDataItems(List<DataItem> items)
        {
            if (items != null && items.Count > 0 && items[0].TagObject!=null)
            {
                foreach (DataItem item in items)
                {
                    item.SubInfo = Newtonsoft.Json.JsonConvert.SerializeObject(item.TagObject);
                }
            }
            return items;
        }

        public virtual List<DataItem> DeSerializeDataItems(List<DataItem> items)
        {
            if (items != null && items.Count > 0 && !string.IsNullOrEmpty(items[0].SubInfo))
            {
                foreach (DataItem item in items)
                {
                    item.TagObject = Newtonsoft.Json.JsonConvert.DeserializeObject<Extra>(item.SubInfo);
                }
            }
            return items;
        }

        public virtual DataItem DeSerializeDataItem(DataItem item)
        {
            item.TagObject = Newtonsoft.Json.JsonConvert.DeserializeObject<Extra>(item.SubInfo);
            return item;
        }
        protected List<DataItem> DeSerialize<T>(List<DataItem> items) where T : Extra
        {
            if (items != null && items.Count > 0 && !string.IsNullOrEmpty(items[0].SubInfo))
            {
                foreach (DataItem item in items)
                {
                    item.TagObject = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(item.SubInfo);
                }
            }
            return items;
        }

        protected DataItem DeSerialize<T>(DataItem item) where T : Extra
        {
            item.TagObject = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(item.SubInfo);
            return item;
        }
        public virtual DataItem DecorateItem(DataItem item)
        {
            return item;
        }

        /// <summary>
        /// 修改数值
        /// </summary>
        /// <param name="dataId">数据项Id</param>
        /// <param name="value">写入值</param>
        /// <returns></returns>
        public abstract RxTxCommand WriteValue(string dataId, double value);

        public abstract RxTxCommand WriteValue(string startId, byte[] buffer);
        /// <summary>
        /// 遥控
        /// </summary>
        /// <param name="rcId">遥控点Id</param>
        /// <param name="on">true：开 false:关</param>
        /// <returns></returns>
        public virtual RxTxCommand RemoteControl(string rcId, bool on)
        {
            var rcItem =   Global.DataAccess.GetRemoteItem(rcId);
            if (rcItem == null) return null;
            if (on)
            {
                return WriteValue(rcItem.RelateItemId, rcItem.OnValue);
            }
            else
            {
                return WriteValue(rcItem.RelateItemId, rcItem.OffValue);
            }
        }
        
        /// <summary>
        /// 直接发送报文
        /// </summary>
        /// <param name="strContent">字符串报文</param>
        /// <returns></returns>
        public virtual RxTxCommand SendMessage(string strContent)
        {
            if (string.IsNullOrEmpty(strContent)) return null;
            ModbusRxTxCommand modIten = new ModbusRxTxCommand(Dev.Id, "插帧报文");
            modIten.SendBytes = Encoding.ASCII.GetBytes(strContent);
            //modIten.DealReceiveMsg = MsgHandler;
            ModbusHelper.MakeSendFrame(ref modIten);
            this.Channel.PutInsertCommand(modIten);
            return modIten;
        }
        /// <summary>
        /// 直接发送报文
        /// </summary>
        /// <param name="byteContent">字节报文</param>
        /// <returns></returns>
        public virtual RxTxCommand SendMessage(byte[] byteContent)
        {
            if (byteContent == null || byteContent.Length==0) return null;
            ModbusRxTxCommand modIten = new ModbusRxTxCommand(Dev.Id, "插帧报文");
            modIten.SendBytes = byteContent;
            //modIten.DealReceiveMsg = MsgHandler;
            ModbusHelper.MakeSendFrame(ref modIten);
            this.Channel.PutInsertCommand(modIten);
            return modIten;
        }

        protected virtual void DealSignal(DataItem dataitem, double prewValue)
        {
            if (Dev == null) return;
            if (Math.Abs(prewValue - dataitem.CurValue) < 0.0000001f)
            {
                return;
            }

            string strEventDesc;
            // ReSharper disable once RedundantCast
            if (((Int64)dataitem.CurValue | (Int64)dataitem.TriggerValue) != 0)
            {
                strEventDesc = "：信号产生";
            }
            else
            {
                strEventDesc = "：信号消失";
            }
            string chlName;

            var channel = Global.DataAccess.GetChannel(Dev.ChannelId);
            var devName = Dev.Name;

            if (channel != null)
            {
                chlName = channel.Name;
            }
            else
            {
                chlName = "";
            }

            try
            {
                Global.DataAccess.AddEvent(EventType.SignalChanged, EventLevel.Warning, chlName + devName + dataitem.Name + strEventDesc);
            }
            catch
            {
            }
        }
    }
}
